/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						 actor_sequence.cpp

	$Header: /heroes4/actor_sequence.cpp $

	$NoKeywords: $

 ************************************************************************/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "actor_sequence.h"

#include <cassert>
#include <map>
#include <utility>

#include "pixel_24.h"
#include "screen_point.h"
#include "streambuf_operators.h"
#include "string_insensitive_compare.h"

// ------------------------------------------------------------------------------
// Unnamed namespace
// ------------------------------------------------------------------------------

namespace
{

	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	int const k_current_format_version = 2;

} // Unname namespace

// ------------------------------------------------------------------------------
// t_actor_sequence_24::t_impl class
// ------------------------------------------------------------------------------

class t_actor_sequence_24::t_impl
{
public:
	// Types
	typedef std::map< std::string, int, t_string_insensitive_less > t_owner_name_map;

	// Data members
	t_owner_name_map	m_owner_name_map;
};

// ------------------------------------------------------------------------------
// t_actor_sequence_24 members
// ------------------------------------------------------------------------------

// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
t_actor_sequence_24::t_actor_sequence_24()
{
}

// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
t_actor_sequence_24::t_actor_sequence_24( t_actor_sequence_24 const & other )
	:	t_image_sequence_24( other ),
		m_impl_ptr( other.m_impl_ptr )
{
}

// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
t_actor_sequence_24::~t_actor_sequence_24()
{
}

// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
void t_actor_sequence_24::add_owner_name( std::string const & new_owner_name )
{
	assert( !new_owner_name.empty() );

	t_impl::t_owner_name_map & owner_name_map = m_impl_ptr->m_owner_name_map;
	t_impl::t_owner_name_map::iterator owner_name_iter = owner_name_map.find( new_owner_name );
	if ( owner_name_iter != owner_name_map.end() )
		++owner_name_iter->second;
	else
		owner_name_map.insert( std::make_pair( new_owner_name, 1 ) );
}

// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
void t_actor_sequence_24::clear_owner_names()
{
	m_impl_ptr->m_owner_name_map.clear();
}

// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
int t_actor_sequence_24::get_owner_name_count() const
{
	return m_impl_ptr->m_owner_name_map.size();
}

// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
void t_actor_sequence_24::get_owner_names( std::vector< std::string > & owner_name_vector ) const
{
	t_impl::t_owner_name_map const & owner_name_map = m_impl_ptr->m_owner_name_map;

	std::vector< std::string > new_owner_name_vector;
	new_owner_name_vector.reserve( owner_name_map.size() );

	t_impl::t_owner_name_map::const_iterator owner_name_iter = owner_name_map.begin();
	for ( ; owner_name_iter != owner_name_map.end(); ++owner_name_iter )
		new_owner_name_vector.push_back( owner_name_iter->first );

	new_owner_name_vector.swap( owner_name_vector );
}

// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
bool t_actor_sequence_24::read( std::streambuf & stream )
{
	t_impl::t_owner_name_map new_owner_name_map;

	try
	{
		int format_version = get< t_uint16 >( stream );
		if ( format_version < 2 )
		{
			std::string owner_name;
			if ( !t_image_sequence_24::read_version( stream, format_version, &owner_name ) )
				return false;

			if ( !owner_name.empty() )
				new_owner_name_map.insert( std::make_pair( owner_name, 1 ) );
		}
		else
		{
			if ( !t_image_sequence_24::read( stream ) )
				return false;

			int num_owner_names = get< t_uint16 >( stream );
			while ( num_owner_names > 0 )
			{
				std::string owner_name;
				stream >> owner_name;
				if ( owner_name.empty() )
					return false;

				int usage_count = get< t_uint16 >( stream );
				if ( usage_count <= 0 )
					return false;

				new_owner_name_map.insert( std::make_pair( owner_name, usage_count ) );

				--num_owner_names;
			}
		}
	}
	catch ( t_streambuf_read_failure const & )
	{
		return false;
	}

	if (	!new_owner_name_map.empty()
		||	!m_impl_ptr.get_const()->m_owner_name_map.empty() )
		new_owner_name_map.swap( m_impl_ptr->m_owner_name_map );
	
	return true;
}

// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
void t_actor_sequence_24::remove_owner_name( std::string const & owner_name )
{
	assert( !owner_name.empty() );

	t_impl::t_owner_name_map & owner_name_map = m_impl_ptr->m_owner_name_map;
	t_impl::t_owner_name_map::iterator owner_name_iter = owner_name_map.find( owner_name );
	if (	owner_name_iter != owner_name_map.end()
		&&	--owner_name_iter->second == 0 )
		owner_name_map.erase( owner_name_iter );
}

// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
bool t_actor_sequence_24::set_frames( t_bitmap_group_24 const & bitmap_group )
{
	if ( !t_image_sequence_24::set_frames( bitmap_group ) )
		return false;

	set_offset( t_screen_point( -361, -347 ) );

	return true;
}

// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
bool t_actor_sequence_24::write( std::streambuf & stream ) const
{
	try
	{
		put< t_uint16 >( stream, k_current_format_version );

		if ( !t_image_sequence_24::write( stream ) )
			return false;

		t_impl::t_owner_name_map const & owner_name_map = m_impl_ptr->m_owner_name_map;

		put< t_uint16 >( stream, owner_name_map.size() );

		t_impl::t_owner_name_map::const_iterator owner_name_iter = owner_name_map.begin();
		for ( ; owner_name_iter != owner_name_map.end(); ++owner_name_iter )
		{
			stream << owner_name_iter->first;
			put< t_uint16 >( stream, owner_name_iter->second );
		}
	}
	catch ( t_streambuf_write_failure const & )
	{
		return false;
	}

	return true;
}

// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
t_actor_sequence_24 & t_actor_sequence_24::operator=( t_actor_sequence_24 const & other )
{
	t_image_sequence_24::operator=( other );
	m_impl_ptr = other.m_impl_ptr;
	return *this;
}

// ------------------------------------------------------------------------------
// t_resource_traits< t_actor_sequence_24 > specialization
// ------------------------------------------------------------------------------

char const t_resource_traits< t_actor_sequence_24 >::prefix[] = "actor_sequence";

char const t_resource_traits< t_actor_sequence_24 >::extension[] = "psd";
